package base.reflection_demo.demo_05;

import lombok.extern.slf4j.Slf4j;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * 动态代理原理演示
 * 通过反射给在核心业务前后分别添加权限校验和日志记录功能
 *
 * 基于子类的动态代理：
 *  涉及的类：Enhancer，由第三方Cglib库提供
 * 如何创建代理对象：
 *  使用Enhancer.create()方法
 * 创建代理对象的要求：
 *  被代理的类不能是最终类
 *
 * create方法参数：
 *  Class字节码：
 *      用于指定被代理对象的字节码
 *
 *  Callback:
 *      用于提供增强的代码，让我们写如何代理的逻辑。
 *      我们一般都是通过匿名内部类提供该接口的一个子接口MethodInterceptor 的实现类。
 *
 */
@Slf4j
public class DynamicProxyTestByCglib {

    public static void main(String[] args) {
        //1.将业务逻辑里面权限和日志功能撇除,通过动态代理实现权限和日志功能
        UserDaoImpl userDaoImpl = new UserDaoImpl();

        UserDaoImpl cglibUserDaoImpl = (UserDaoImpl) Enhancer.create(UserDaoImpl.class, new MethodInterceptor() {
            /**
             *
             * @param proxy
             * @param method
             * @param args
             * 以上参数和基于接口的动态代理中invoke（）方法参数是一样的。
             * @param methodProxy 几乎用不上
             * @return  和被代理对象方法执行返回值类型一样
             * @throws Throwable
             */
            @Override
            public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                log.info("权限校验");
                Object result = method.invoke(userDaoImpl, args);// 通过反射调用 target对象上的 method方法,返回返回值
                log.info("日志记录");
                log.info("Handler ->  proxy:{}, method:{}, args:{}, result:{}", proxy,method,args,result);
                return result;
            }
        });
        log.info("Test -> proxy:{}", cglibUserDaoImpl);

        cglibUserDaoImpl.register();
        cglibUserDaoImpl.login();
    }
}
